package cn.woochen.comlib

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.kingja.loadsir.core.LoadService
import com.kingja.loadsir.core.LoadSir
import cn.woochen.comlib.config.IBaseView
import cn.woochen.comlib.loadinglayout.EmptyCallBack
import cn.woochen.comlib.loadinglayout.ErrorCallback
import cn.woochen.comlib.loadinglayout.LoadingCallBack
import cn.woochen.comlib.loadinglayout.LoadingHasContentCallBack
import kotlinx.coroutines.launch
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

abstract class BaseLibraryFragment<DB : ViewDataBinding, VM : BaseViewModel> : Fragment(),
    IBaseView {

    protected val mContext by lazy {
        requireActivity()
    }

    protected lateinit var mBinding: DB
        private set

    protected lateinit var mViewModel: VM

    protected lateinit var loadService: LoadService<*>

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        mBinding = DataBindingUtil.inflate(inflater, setContentView(), container, false)
        mViewModel = createViewModel()
        loadService = LoadSir.getDefault().register(mBinding.root)
        mContext.window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM)
        registerNecessaryObserver()
        initListener()
        initData()
        return loadService.loadLayout
    }

    private fun createViewModel(): VM {
        return ViewModelProvider(this).get(getVmClazz(this))
    }

    /**
     * 获取任意对象的泛型信息，返回一个继承了BaseViewModel的字节码对象
     */
    private fun getVmClazz(obj: Any): Class<VM> {
        var cls: Class<*>? = obj.javaClass
        var vmClass: Class<VM>? = null
        while (vmClass == null && cls != null) {
            vmClass = getVMClass(cls)
            cls = cls.superclass
        }
        if (vmClass == null) {
            vmClass = BaseViewModel::class.java as Class<VM>
        }
        return vmClass
    }

    private fun getVMClass(cls: Class<*>): Class<VM>? {
        val type: Type? = cls.genericSuperclass
        if (type is ParameterizedType) {
            val types: Array<Type> = type.actualTypeArguments
            for (t in types) {
                if (t is Class<*>) {
                    if (BaseViewModel::class.java.isAssignableFrom(t)) {
                        return t as Class<VM>
                    }
                } else if (t is ParameterizedType) {
                    val rawType: Type = t.rawType
                    if (rawType is Class<*>) {
                        if (BaseViewModel::class.java.isAssignableFrom(rawType)) {
                            return rawType as Class<VM>
                        }
                    }
                }
            }
        }
        return null
    }

    protected abstract fun setContentView(): Int

    protected open fun initListener() {}

    /**
     * 网络请求数据
     */
    protected open fun requestData() {}

    protected abstract fun initData()

    override fun showContent() {
        loadService.showSuccess()
    }

    override fun showEmpty() {
        loadService.showCallback(EmptyCallBack::class.java)
    }

    override fun showLoading(content: String) {
        loadService.showCallback(LoadingHasContentCallBack::class.java)
    }

    override fun showError() {
        loadService.showCallback(ErrorCallback::class.java)
    }

    /**
     * 注册 UI 事件
     */
    protected open fun registerNecessaryObserver() {
        lifecycleScope.launch {
            mViewModel.loadingChange.showDialog.collect {
                showLoading(it)
            }
        }
        lifecycleScope.launch {
            mViewModel.loadingChange.dismissDialog.collect {
                showContent()
            }
        }
    }

}